WPFのDataGridは便利ですが、 1万件を超えると一気に重くなるという弱点があります。 特にSQLiteと組み合わせた業務アプリでは、 「検索結果が多い」「スクロールが重い」「UIが固まる」などの問題が頻発します。
この記事では、SQLite × WPF DataGridで大量データを扱う際の 高速化テクニックを体系的にまとめた実務ガイドです。
・DataGridが重くなる根本原因
・仮想化(Virtualization)の正しい設定
・ページング(LIMIT/OFFSET)
・非同期読み込み(async/await)
・遅延ロード(Lazy Loading)
・Dapper/EF Coreの最適化
・業務アプリ向けベストプラクティス
1. DataGridが重くなる根本原因
WPF DataGridが重くなる理由は次の3つです。
- UIに大量の行を描画しようとする
- SQLiteから全件読み込んでしまう
- UIスレッドでDBアクセスしている
つまり、解決策は次の3つ。
- UIは必要な行だけ描画(仮想化)
- DBは必要な件数だけ取得(ページング)
- 読み込みは非同期で行う(async/await)
2. DataGridの仮想化を必ずONにする
WPF DataGridはデフォルトで仮想化がONですが、 スタイルやテンプレートをいじると無効になることがあります。
■ 正しい仮想化設定
<DataGrid
EnableRowVirtualization="True"
EnableColumnVirtualization="True"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.ScrollUnit="Pixel"
VirtualizingPanel.VirtualizationMode="Recycling"
/>
■ ポイント
- ScrollUnit="Pixel" → スクロールが滑らか
- Recycling → 行の再利用で高速化
3. SQLiteは「全件取得」すると一気に遅くなる
SQLiteは軽量ですが、 1万件以上を一気にSELECTするとUIが固まることがあります。
そこで必要なのが、次の2つ。
- LIMIT / OFFSET でページング
- 検索条件を必ず付ける
■ ページングSQL(SQLite)
SELECT * FROM Users
ORDER BY Id
LIMIT @limit OFFSET @offset;
■ C#(Dapper)
var users = await con.QueryAsync<User>(
"SELECT * FROM Users ORDER BY Id LIMIT @limit OFFSET @offset",
new { limit = 100, offset = page * 100 }
);
1ページ100件が最もバランスが良いです。
4. 非同期読み込み(UIフリーズ防止)
UIスレッドでDBアクセスすると、 DataGridが固まる → “アプリが落ちた”と誤解される という最悪のUXになります。
■ async/awaitで非同期化
public async Task LoadPageAsync(int page)
{
IsLoading = true;
var data = await _repo.GetUsersAsync(page);
Users.Clear();
foreach (var u in data)
Users.Add(u);
IsLoading = false;
}
UIは常に応答し続けるため、体感速度が大幅に向上します。
5. DataTable.Load は同期 → Task.Runで逃がす
DataTable.Load(reader) は同期処理で重いため、 Task.Run で別スレッドに逃がすのが正解。
await Task.Run(() => dt.Load(reader));
6. 遅延ロード(Lazy Loading)で高速化
DataGridにバインドするコレクションを 必要なときだけ読み込む方式にするとさらに高速化できます。
■ ObservableCollection を使わないパターン
大量データでは ObservableCollection が重くなるため、 IEnumerable を直接 ItemsSource に渡す方が高速です。
DataGrid.ItemsSource = await _repo.GetUsersAsync(page);
7. 大量データ × DataGrid の最適構成
実務で最も安定する構成はこれ。
- SQLite:LIMIT/OFFSETでページング
- Dapper:高速クエリ
- ViewModel:async/awaitで非同期読み込み
- DataGrid:仮想化ON
- ItemsSource:IEnumerableを直接渡す
8. UI側の高速化テクニック
■ 列のAutoサイズを禁止
ColumnWidth="*" />
Auto は全行を測定するため激重。
■ CellTemplateを使いすぎない
テンプレートが多いと描画コストが跳ね上がる。
■ AlternationCountを使わない
交互色は軽いが、複雑なスタイルは重い。
9. 業務アプリ向けベストプラクティス
- DataGridの仮想化を必ずON
- SQLiteはLIMIT/OFFSETでページング
- UIスレッドでDBアクセスしない(async/await)
- DataTable.LoadはTask.Runで逃がす
- ObservableCollectionは大量データに不向き
- Autoサイズ・複雑テンプレートは避ける
- 検索条件を必ず付ける(全件取得禁止)
まとめ:DataGrid高速化は“DB・UI・非同期”の三位一体
- SQLite側:ページングで必要な件数だけ取得
- UI側:仮想化で必要な行だけ描画
- アプリ側:非同期でUIフリーズを防ぐ
「DataGridが重い」のはWPFの限界ではなく、 設計次第で1〜5万件でもサクサク動くアプリにできます。 この記事のパターンをベースに、あなたのアプリに最適な高速化を実装してみてください。